﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Input;
using BabyCloudDrives.DesktopApp.Models;
using BabyCloudDrives.DesktopApp.Utilities;
using BabyCloudDrives.DesktopApp.ViewModels.Base;

namespace BabyCloudDrives.DesktopApp.ViewModels
{
    public class SkyDriveViewModel : ObservableObject
    {
        private const string ApiUrlFormat = "https://apis.live.net/v5.0/{0}?access_token={1}";
        private bool _isLoading;
        private string _loadingMessage;
        private IList<SkyDriveFolder> _skyDriveFolders;
        private SkyDriveQuota _quota;
        private bool _isShowFolderList;
        private bool _isShowFileList;
        private IList<SkyDriveFile> _selectedSkyDriveFiles;
        private SkyDriveEntryBase _selectedFolder;
        private bool _accessTokenCanWork;
        private string _downloadPath;
        private bool _isShowDownloadProgressBar;
        private long _progressMaxVal;
        private long _progressCurrentVal;

        public bool IsLoading
        {
            get { return _isLoading; }
            set
            {
                _isLoading = value;
                OnPropertyChanged("IsLoading");
            }
        }

        public string LoadingMessage
        {
            get { return _loadingMessage; }
            set
            {
                _loadingMessage = value;
                OnPropertyChanged("LoadingMessage");
            }
        }

        public IList<SkyDriveFolder> SkyDriveFolders
        {
            get { return _skyDriveFolders; }
            set
            {
                _skyDriveFolders = value;
                OnPropertyChanged("SkyDriveFolders");
            }
        }

        public IList<SkyDriveFile> SelectedSkyDriveFiles
        {
            get { return _selectedSkyDriveFiles; }
            set
            {
                _selectedSkyDriveFiles = value;
                OnPropertyChanged("SelectedSkyDriveFiles");
            }
        }

        public SkyDriveQuota Quota
        {
            get { return _quota; }
            set
            {
                _quota = value;
                OnPropertyChanged("Quota");
            }
        }

        public bool IsShowFolderList
        {
            get { return _isShowFolderList; }
            set
            {
                _isShowFolderList = value;
                OnPropertyChanged("IsShowFolderList");
            }
        }

        public bool IsShowFileList
        {
            get { return _isShowFileList; }
            set
            {
                _isShowFileList = value;
                OnPropertyChanged("IsShowFileList");
            }
        }

        public SkyDriveEntryBase SelectedFolder
        {
            get { return _selectedFolder; }
            set
            {
                _selectedFolder = value;
                OnPropertyChanged("SelectedFolder");
            }
        }

        public SkyDriveUser SkyDriveUser { get; set; }

        public bool AccessTokenCanWork
        {
            get { return _accessTokenCanWork; }
            set
            {
                _accessTokenCanWork = value;
                OnPropertyChanged("AccessTokenCanWork");
            }
        }

        public string DownloadPath
        {
            get { return _downloadPath; }
            set
            {
                _downloadPath = value;
                OnPropertyChanged("DownloadPath");
            }
        }

        public long ProgressMaxVal
        {
            get { return _progressMaxVal; }
            set
            {
                _progressMaxVal = value;
                OnPropertyChanged("ProgressMaxVal");
            }
        }

        public long ProgressCurrentVal
        {
            get { return _progressCurrentVal; }
            set
            {
                _progressCurrentVal = value;
                OnPropertyChanged("ProgressCurrentVal");
            }
        }

        public bool IsShowDownloadProgressBar
        {
            get { return _isShowDownloadProgressBar; }
            set
            {
                _isShowDownloadProgressBar = value;
                OnPropertyChanged("IsShowDownloadProgressBar");
            }
        }

        public ICommand OnLoadFolder { get; set; }
        public ICommand OnOpenFolder { get; set; }
        public ICommand BackCommand { get; set; }
        public ICommand LoadCompleted { get; set; }
        public ICommand DownloadCommand { get; set; }


        public SkyDriveViewModel()
        {
            OnLoadFolder = new ActionCommand(LoadFolderHandle);
            OnOpenFolder = new ActionCommand(OpenFolderHandle);
            BackCommand = new ActionCommand(BackHandle);
            LoadCompleted = new ActionCommand(TryGetUserData);
            DownloadCommand = new ActionCommand(Download);
        }

        private void Download(object skyDriveEntryObj)
        {
            var skyDriveEntry = skyDriveEntryObj as SkyDriveEntryBase;
            if (skyDriveEntry == null || string.IsNullOrEmpty(DownloadPath)) return;
            string downloadUrl = string.Format(ApiUrlFormat, skyDriveEntry.Id + "/content",
                                               PresetValues.ResponseValue.AccessToken);
            IsLoading = true;
            IsShowDownloadProgressBar = true;
            RESTUtility.DownloadFile(new Uri(downloadUrl), Path.Combine(DownloadPath, skyDriveEntry.Name),
                                     (sender, args) =>
                                         {
                                             ProgressMaxVal = args.TotalBytesToReceive;
                                             ProgressCurrentVal = args.BytesReceived;
                                             LoadingMessage =
                                                 string.Format("{0}    downloaded {1} of {2} MB. {3} % complete...",
                                                               (string) args.UserState,
                                                               string.Format("{0:0.00}",
                                                                             (float) args.BytesReceived/1024000),
                                                               string.Format("{0:0.00}",
                                                                             (float) args.TotalBytesToReceive/1024000),
                                                               args.ProgressPercentage);
                                         },
                                     (sender, args) =>
                                         {
                                             IsShowDownloadProgressBar = false;
                                             IsLoading = false;
                                             DownloadPath = string.Empty;
                                         });
        }

        private void LoadFolderHandle()
        {
            if (string.IsNullOrEmpty(PresetValues.ResponseValue.AccessToken)) return;
            IsLoading = true;
            ShowLoadingMessage("Loading folders now", () => IsLoading);
            new Action(() =>
                {
                    Uri getFoldersUri =
                        new Uri(string.Format(ApiUrlFormat, "me/skydrive/files",
                                              PresetValues.ResponseValue.AccessToken));
                    var result = RESTUtility.GetData<SkyDriveResults<SkyDriveFolder>>(getFoldersUri);
                    SkyDriveFolders = result.Data;
                    IsShowFileList = false;
                    IsShowFolderList = true;
                    IsLoading = false;
                }).BeginInvoke(null, null);
            new Action(() =>
                {
                    Uri getQuotaUri = new Uri(string.Format(ApiUrlFormat, "me/skydrive/quota",
                                                            PresetValues.ResponseValue.AccessToken));
                    Quota = RESTUtility.GetData<SkyDriveQuota>(getQuotaUri);
                }).BeginInvoke(null, null);
        }

        private void OpenFolderHandle(object skyDriveFolderObj)
        {
            var skyDriveEntry = skyDriveFolderObj as SkyDriveEntryBase;
            if ((skyDriveEntry == null || skyDriveEntry.Type != "folder") && !(skyDriveFolderObj is SkyDriveFolder))
                return;
            if (skyDriveEntry.ChildFiles != null)
            {
                SelectedSkyDriveFiles = skyDriveEntry.ChildFiles;
                SelectedFolder = skyDriveEntry;
                IsShowFileList = true;
                IsShowFolderList = false;
                return;
            }
            IsLoading = true;
            ShowLoadingMessage("Loading files now", () => IsLoading);
            new Action(() =>
                {
                    Uri getFilesUri =
                        new Uri(string.Format(ApiUrlFormat, string.Format("{0}/files", skyDriveEntry.Id),
                                              PresetValues.ResponseValue.AccessToken));
                    var result = RESTUtility.GetData<SkyDriveResults<SkyDriveFile>>(getFilesUri);
                    skyDriveEntry.ChildFiles = SelectedSkyDriveFiles = result.Data;
                    SelectedFolder = skyDriveEntry;
                    foreach (var folderOfFiles in SelectedSkyDriveFiles.Where(p => p.Type == "folder"))
                    {
                        folderOfFiles.ParentFolder = SelectedFolder;
                    }
                    IsShowFolderList = false;
                    IsShowFileList = true;
                    IsLoading = false;
                }).BeginInvoke(null, null);
        }

        private void BackHandle()
        {
            if (SelectedFolder == null) return;
            if (SelectedFolder.ParentFolder == null)
            {
                SelectedFolder = null;
                IsShowFolderList = true;
                IsShowFileList = false;
            }
            else
            {
                SelectedSkyDriveFiles = SelectedFolder.ParentFolder.ChildFiles;
                SelectedFolder = SelectedFolder.ParentFolder;
            }
        }

        private void TryGetUserData()
        {
            string getUserUrl = string.Format("https://apis.live.net/v5.0/me?access_token={0}",
                                              PresetValues.ResponseValue.AccessToken);
            try
            {
                SkyDriveUser = RESTUtility.GetData<SkyDriveUser>(new Uri(getUserUrl));
            }
            catch (InvalidOperationException ex)
            {
                if (ex.Message.Contains("401"))
                    PresetValues.ResponseValue.AccessToken = null;
            }
            AccessTokenCanWork = SkyDriveUser != null;
            if (SkyDriveUser != null)
                LoadFolderHandle();
        }

        private void ShowLoadingMessage(string currentMessage, Func<bool> canBeInvokeFun)
        {
            new Action(() =>
                {
                    string dotStr = ".";
                    LoadingMessage = currentMessage;
                    while (canBeInvokeFun())
                    {
                        dotStr += ".";
                        if (dotStr.Length > 6) dotStr = ".";
                        LoadingMessage = currentMessage + dotStr;
                        Thread.Sleep(300);
                    }
                }).BeginInvoke(null, null);
        }
    }
}